/****************************************************************************
** \file HttpServer.cpp
** \company PONGBOT
**
** \author houhaotian
** \date 2020/09/14
**
** \brief 
**
** 
*****************************************************************************/

#include "HttpServer.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include "HttpRequest.h"
#include <QNetworkInterface>
#include <QDebug>

HttpServer::HttpServer(QObject *parent)
    : QObject(parent)
{
    m_server = new QTcpServer(this);
    listen();
}

HttpServer::~HttpServer()
{
}

void HttpServer::onClientDisconnected()
{
    qDebug() << "disconnect from remote";
    delete m_request;
    sender()->deleteLater();
}

void HttpServer::close()
{
    m_server->close();
}

void HttpServer::listen()
{
    if (m_server->isListening())
        return;
	QHostAddress host = QNetworkInterface::interfaceFromName("eth0").addressEntries().first().ip();
	//QNetworkInterface::interfaceFromName("wlan0").addressEntries().first().ip();
	m_server->listen(host, 8000);
	m_server->setMaxPendingConnections(1);
	connect(m_server, &QTcpServer::newConnection, this, &HttpServer::onNewConnection);
}

void HttpServer::restartListen()
{
    close();
    listen();
}

void HttpServer::onNewConnection()
{
    if (m_server->hasPendingConnections()) {
        qDebug() << "http established";
        m_request = new HttpRequest;
        QTcpSocket *socket = m_server->nextPendingConnection();
        connect(socket, &QIODevice::readyRead, this, &HttpServer::onRead);
        connect(socket, &QTcpSocket::disconnected, this, &HttpServer::onClientDisconnected);
    }
}

void HttpServer::onRead()
{
    QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());

    // The loop adds support for HTTP pipelinig
    while (socket->bytesAvailable()) {
        // Create new HttpRequest object if necessary
        /*if (!m_request) {
            m_request = new HttpRequest(settings);
        }*/

        // Collect data for the request object
        while (socket->bytesAvailable() && m_request->getStatus() != HttpRequest::complete && m_request->getStatus() != HttpRequest::abort) {
            m_request->readFromSocket(socket);
            //if (m_request->getStatus() == HttpRequest::waitForBody) {
            //    // Restart timer for read timeout, otherwise it would
            //    // expire during large file uploads.
            //    int readTimeout = settings->value("readTimeout", 10000).toInt();
            //    readTimer.start(readTimeout);
            //}
        }

        // If the request is aborted, return error message and close the connection
        if (m_request->getStatus() == HttpRequest::abort) {
            socket->write("HTTP/1.1 413 entity too large\r\nConnection: close\r\n\r\n413 Entity too large\r\n");
            while (socket->bytesToWrite()) socket->waitForBytesWritten();
            socket->disconnectFromHost();
            m_request->reset();
            return;
        }
        if (m_request->getStatus() == HttpRequest::complete) {
            //HttpResponse response;
            emit service(*m_request, socket);
            m_request->reset();
        }

        // //If the request is complete, let the request mapper dispatch it
        //if (m_request->getStatus() == HttpRequest::complete) {
        //     //Copy the Connection:close header to the response
        //    HttpResponse response(socket);
        //    bool closeConnection = QString::compare(m_request->getHeader("Connection"), "close", Qt::CaseInsensitive) == 0;
        //    if (closeConnection)
        //    {
        //        response.setHeader("Connection", "close");
        //    }

        //     //In case of HTTP 1.0 protocol add the Connection:close header.
        //     //This ensures that the HttpResponse does not activate chunked mode, which is not spported by HTTP 1.0.
        //    else
        //    {
        //        bool http1_0 = QString::compare(m_request->getVersion(), "HTTP/1.0", Qt::CaseInsensitive) == 0;
        //        if (http1_0)
        //        {
        //            closeConnection = true;
        //            response.setHeader("Connection", "close");
        //        }
        //    }

        //    // Call the request mapper
        //    try
        //    {
        //        requestHandler->service(*m_request, response);
        //    }
        //    catch (...)
        //    {
        //        qCritical("HttpConnectionHandler (%p): An uncatched exception occured in the request handler",
        //            static_cast<void *>(this));
        //    }

        //    // Finalize sending the response if not already done
        //    if (!response.hasSentLastPart())
        //    {
        //        response.write(QByteArray(), true);
        //    }

        //    qDebug("HttpConnectionHandler (%p): finished request", static_cast<void *>(this));

        //    // Find out whether the connection must be closed
        //    if (!closeConnection)
        //    {
        //        // Maybe the request handler or mapper added a Connection:close header in the meantime
        //        bool closeResponse = QString::compare(response.getHeaders().value("Connection"), "close", Qt::CaseInsensitive) == 0;
        //        if (closeResponse == true)
        //        {
        //            closeConnection = true;
        //        }
        //        else
        //        {
        //            // If we have no Content-Length header and did not use chunked mode, then we have to close the
        //            // connection to tell the HTTP client that the end of the response has been reached.
        //            bool hasContentLength = response.getHeaders().contains("Content-Length");
        //            if (!hasContentLength)
        //            {
        //                bool hasChunkedMode = QString::compare(response.getHeaders().value("Transfer-Encoding"), "chunked", Qt::CaseInsensitive) == 0;
        //                if (!hasChunkedMode)
        //                {
        //                    closeConnection = true;
        //                }
        //            }
        //        }
        //    }

        //    // Close the connection or prepare for the next request on the same connection.
        //    if (closeConnection)
        //    {
        //        while (socket->bytesToWrite()) socket->waitForBytesWritten();
        //        socket->disconnectFromHost();
        //    }
        //    else
        //    {
        //        // Start timer for next request
        //        int readTimeout = settings->value("readTimeout", 10000).toInt();
        //        readTimer.start(readTimeout);
        //    }
        //    delete m_request;
        //    m_request = nullptr;
       // }
    }
}
